home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / Games / xmris / draw.c < prev    next >
C/C++ Source or Header  |  1995-05-03  |  24KB  |  816 lines

  1. /*{{{  (C) 1992 Nathan Sidwell*/
  2. /*****************************************************************************
  3.             X M R I S V1.01
  4.             ---------------
  5.             (C) 1992 Nathan Sidwell
  6.  
  7. This program is copyright (C) 1992 Nathan Sidwell. This software and documentation
  8. is in the public domain. Permission is granted to distribute and compile
  9. verbatim copies of this software for non-commercial, non-profit use,
  10. without fee. The software may be modified, provided that both the above copyright
  11. notice and this permission notice appear.
  12.  
  13. No guarantee is given as to the robustness or suitability of this
  14. software for your computer.
  15.  
  16. Nathan Sidwell  INMOS UK |                 | nathan@inmos.co.uk       DoD#0390
  17. *****************************************************************************/
  18. /*}}}*/
  19. #include "xmris.h"
  20. #include "time.h"
  21. /*{{{  prototypes*/
  22. static void xor_ball PROTOARGLIST((void));
  23. /*}}}*/
  24. /*{{{  void add_background(x, y, w, h)*/
  25. extern void add_background FUNCARGLIST((x, y, width, height))
  26. int       x       FUNCARGSEP
  27. int       y       FUNCARGSEP
  28. int       width   FUNCARGSEP
  29. int       height  FUNCARGTERM
  30. /*
  31.  * adds an area to the background update list
  32.  */
  33. {
  34.   BACKGROUND *bptr;
  35.  
  36.   assert(update.back.backs != BACK_UPDATES);
  37.   bptr = &update.back.list[update.back.backs++];
  38.   bptr->place.x = x;
  39.   bptr->place.y = y;
  40.   bptr->size.x = width;
  41.   bptr->size.y = height;
  42.   return;
  43. }
  44. /*}}}*/
  45. /*{{{  void bounding_box(x, y, width, height)*/
  46. extern void bounding_box FUNCARGLIST((x, y, width, height))
  47. int       x       FUNCARGSEP
  48. int       y       FUNCARGSEP
  49. unsigned  width   FUNCARGSEP
  50. unsigned  height  FUNCARGTERM
  51. /*
  52.  * updates the update box so that it includes the
  53.  * supplied rectangle/
  54.  * remember to empty the update box to the background list
  55.  */
  56. {
  57.   if(!update.set)
  58.     {
  59.       update.br.x = (update.tl.x = x) + width;
  60.       update.br.y = (update.tl.y = y) + height;
  61.       update.set = 1;
  62.     }
  63.   else
  64.     {
  65.       if(update.tl.x > x)
  66.     update.tl.x = x;
  67.       if(update.tl.y > y)
  68.     update.tl.y = y;
  69.       if(update.br.x < (int)(x + width))
  70.     update.br.x = (int)(x + width);
  71.       if(update.br.y < (int)(y + height))
  72.     update.br.y = (int)(y + height);
  73.     }
  74.   return;
  75. }
  76. /*}}}*/
  77. /*{{{  void draw_center(index)*/
  78. extern void draw_center FUNCARGLIST((index))
  79. int   index FUNCARGTERM
  80. /*
  81.  * sets the center sprite and draws it on the background
  82.  */
  83. {
  84.   SPRITE    *sptr;
  85.  
  86.   BOARDCELL(DEN_X, DEN_Y)->sprite = index;
  87.   add_background(PIXELX(DEN_X, 0), PIXELY(DEN_Y, 0), CELL_WIDTH, CELL_HEIGHT);
  88.   XFillRectangle(display.display, display.back, GCN(GC_CLEAR),
  89.       PIXELX(DEN_X, 0), PIXELY(DEN_Y, 0), CELL_WIDTH, CELL_HEIGHT);
  90.   sptr = &sprites[index];
  91.   if(display.background != COLOUR_ZERO)
  92.     XCopyArea(display.display, sptr->mask, display.back, GCN(GC_MASK),
  93.     0, 0, CELL_WIDTH, CELL_HEIGHT, PIXELX(DEN_X, 0), PIXELY(DEN_Y, 0));
  94.   XCopyArea(display.display, sptr->image, display.back, GCN(GC_OR),
  95.       0, 0, CELL_WIDTH, CELL_HEIGHT, PIXELX(DEN_X, 0), PIXELY(DEN_Y, 0));
  96.   return;
  97. }
  98. /*}}}*/
  99. /*{{{  void draw_extra()*/
  100. extern void draw_extra FUNCARGVOID
  101. {
  102.   int       x;
  103.   SPRITE    *sptr;
  104.   
  105.   x = XTRA_X + extra.select * XTRA_SPACING;
  106.   sptr = &sprites[SPRITE_XTRA + (random() & 1)];
  107.   XCopyArea(display.display, sptr->mask, display.back, GCN(GC_MASK),
  108.       0, 0, CELL_WIDTH, CELL_HEIGHT, x, XTRA_Y);
  109.   XCopyArea(display.display, sptr->image, display.back, GCN(GC_OR),
  110.       0, 0, CELL_WIDTH, CELL_HEIGHT, x, XTRA_Y);
  111.   add_background(x, XTRA_Y, CELL_WIDTH, CELL_HEIGHT);
  112.   return;
  113. }
  114. /*}}}*/
  115. /*{{{  void new_board()*/
  116. extern void new_board FUNCARGVOID
  117. /*
  118.  * sets up a new board
  119.  */
  120. {
  121.   BOARD const *map;
  122.  
  123.   player.screen++;
  124.   map = &boards[player.screen % BOARDS];
  125.   /*{{{  clear board array*/
  126.   {
  127.     unsigned  i;
  128.     CELL      *ptr;
  129.     
  130.     for(i = sizeof(board) / sizeof(board[0]), ptr = board; i--; ptr++)
  131.       {
  132.     ptr->depths[0] = 0;
  133.     ptr->depths[1] = 0;
  134.     ptr->depths[2] = 0;
  135.     ptr->depths[3] = 0;
  136.     ptr->visit = 0;
  137.     ptr->distance = 0;
  138.     ptr->sprite = 0;
  139.       }
  140.   }
  141.   /*}}}*/
  142.   /*{{{  draw blank background*/
  143.   {
  144.     /*{{{  set context*/
  145.     {
  146.       XGCValues gcv;
  147.       
  148.       gcv.fill_style = FillTiled;
  149.       gcv.tile = sprites[SPRITE_FILL_BASE + map->fill].image;
  150.       XChangeGC(display.display, GCN(GC_BOARD), GCTile | GCFillStyle, &gcv);
  151.     }
  152.     /*}}}*/
  153.     XFillRectangle(display.display, display.back, GCN(GC_CLEAR),
  154.     0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
  155.     XFillRectangle(display.display, display.back, GCN(GC_BOARD),
  156.     BORDER_LEFT, BORDER_TOP, BOARD_WIDTH, BOARD_HEIGHT);
  157.     XFillRectangle(display.display, display.back, GCN(GC_CLEAR),
  158.     PIXELX(DEN_X, -GAP_WIDTH / 2), PIXELY(DEN_Y, -GAP_HEIGHT / 2),
  159.     CELL_WIDTH + GAP_WIDTH, CELL_HEIGHT + GAP_HEIGHT);
  160.     XFillRectangle(display.display, display.back, GCN(GC_CLEAR),
  161.     BORDER_LEFT + (CELL_WIDTH + GAP_WIDTH) * 4 + GAP_WIDTH, BORDER_TOP,
  162.     XTRA_SPACING * 4 + CELL_WIDTH, GAP_HEIGHT * 2);
  163.     XDrawRectangle(display.display, display.back, GCN(GC_SET),
  164.     XTRA_X - 1, XTRA_Y - 1,
  165.     XTRA_SPACING * 4 + CELL_WIDTH + 1, CELL_HEIGHT + 1);
  166.     XDrawRectangle(display.display, display.back, GCN(GC_SET),
  167.     BORDER_LEFT, BORDER_TOP,
  168.     BOARD_WIDTH - 1, BOARD_HEIGHT - 1);
  169.   }
  170.   /*}}}*/
  171.   /*{{{  add the xtra*/
  172.   {
  173.     unsigned  i;
  174.       
  175.     extra.escape = 0;
  176.     for(i = 5; i--;)
  177.       draw_extra_letter(i);
  178.     draw_extra();
  179.   }
  180.   /*}}}*/
  181.   /*{{{  add the screen number*/
  182.   {
  183.     char      text[10];
  184.     int       length;
  185.     int       ascent, descent;
  186.     int       direction;
  187.     XCharStruct chars;
  188.       
  189.     strcpy(text, "Screen ");
  190.     length = 7 + itoa(text + 7, player.screen, 0);
  191.     XQueryTextExtents(display.display, font.font, text, length,
  192.       &direction, &ascent, &descent, &chars);
  193.     XDrawImageString(display.display, display.back, GCN(GC_TEXT),
  194.     BORDER_LEFT + (CELL_WIDTH + GAP_WIDTH) * 8 +
  195.     CELL_WIDTH / 2 + GAP_WIDTH, (CELL_HEIGHT - ascent - descent) / 2 +
  196.     ascent + BORDER_TOP - CELL_HEIGHT, text, length);
  197.   }
  198.   /*}}}*/
  199.   add_score(0, 0, 0);
  200.   /*{{{  add lives*/
  201.   if(player.lives)
  202.     {
  203.       unsigned  lives;
  204.       SPRITE    *sptr;
  205.       
  206.       sptr = &sprites[SPRITE_PLAYER + 6];
  207.       for(lives = player.lives - 1; lives--;)
  208.     {
  209.       unsigned  x, y;
  210.         
  211.       x = PIXELX(lives, 0);
  212.       y = PIXELY(CELLS_DOWN, 0);
  213.       XCopyArea(display.display, sptr->mask, display.back, GCN(GC_MASK),
  214.           0, 0, CELL_WIDTH, CELL_HEIGHT, x, y);
  215.       XCopyArea(display.display, sptr->image, display.back, GCN(GC_OR),
  216.           0, 0, CELL_WIDTH, CELL_HEIGHT, x, y);
  217.     }
  218.     }
  219.   /*}}}*/
  220.   /*{{{  copy the map*/
  221.   {
  222.     char const *mptr;
  223.     CELL      *cptr;
  224.     unsigned  y, x;
  225.     
  226.     mptr = (char const *)map->map;
  227.     cptr = BOARDCELL(0, 0);
  228.     for(y = CELLS_DOWN; y--; cptr += CELL_STRIDE - CELLS_ACROSS)
  229.       for(x = CELLS_ACROSS; x--; mptr++, cptr++)
  230.     {
  231.       switch(*mptr)
  232.       {
  233.         /*{{{  case '@': (cherry)*/
  234.         case '@':
  235.           cptr->sprite = SPRITE_CHERRY;
  236.           break;
  237.         /*}}}*/
  238.         /*{{{  case 'X': (path)*/
  239.         case 'X':
  240.           cptr[0].visit = 1;
  241.           if(cptr[-1].visit)
  242.         {
  243.           cptr[-1].depths[3] = CELL_WIDTH + GAP_WIDTH;
  244.           cptr[0].depths[2] = -(CELL_WIDTH + GAP_WIDTH);
  245.         }
  246.           if(cptr[-CELL_STRIDE].visit)
  247.         {
  248.           cptr[-CELL_STRIDE].depths[1] = CELL_HEIGHT + GAP_HEIGHT;
  249.           cptr[0].depths[0] = -(CELL_HEIGHT + GAP_HEIGHT);
  250.         }
  251.           break;
  252.         /*}}}*/
  253.       }
  254.     }
  255.   }
  256.   /*}}}*/
  257.   /*{{{  add the apples*/
  258.   {
  259.     unsigned  i;
  260.     
  261.     apple.apples = 0;
  262.     for(i = INITIAL_APPLES; i--;)
  263.       {
  264.     unsigned  y, x;
  265.     unsigned  j;
  266.     CELL      *cptr;
  267.     APPLE     *aptr;
  268.       
  269.     do
  270.       {
  271.         do
  272.           j = random();
  273.         while(j >= CELLS_ACROSS * (CELLS_DOWN - 1));
  274.         x = j % CELLS_ACROSS;
  275.         y = j / CELLS_ACROSS;
  276.         cptr = BOARDCELL(x, y);
  277.         for(aptr = apple.list, j = apple.apples; j--; aptr++)
  278.           if(aptr->cell.x == x && aptr->cell.y == y)
  279.         {
  280.           aptr = NULL;
  281.           break;
  282.         }
  283.       }
  284.     while(cptr->visit || cptr->sprite || cptr[CELL_STRIDE].visit || !aptr);
  285.     spawn_apple(x, y, 0, 0);
  286.       }
  287.   }
  288.   /*}}}*/
  289.   /*{{{  cut the background*/
  290.   {
  291.     unsigned  y, x;
  292.     COORD     cell;
  293.     CELL      *cptr;
  294.     
  295.     cptr = BOARDCELL(0, 0);
  296.     cell.x = GAP_WIDTH + BORDER_LEFT;
  297.     cell.y = GAP_HEIGHT + BORDER_TOP;
  298.     for(y = CELLS_DOWN; y--; cptr += CELL_STRIDE - CELLS_ACROSS,
  299.     cell.x -= (CELL_WIDTH + GAP_WIDTH) * CELLS_ACROSS,
  300.     cell.y += CELL_HEIGHT + GAP_HEIGHT)
  301.       for(x = CELLS_ACROSS; x--; cptr++, cell.x += CELL_WIDTH + GAP_WIDTH)
  302.     if(cptr->visit)
  303.       munch_hole(cptr, cell.x, cell.y);
  304.     else if(cptr->sprite)
  305.       {
  306.         SPRITE    *sptr;
  307.       
  308.         sptr = &sprites[SPRITE_CHERRY];
  309.         XCopyArea(display.display, sptr->mask, display.back, GCN(GC_MASK),
  310.         0, 0, CELL_WIDTH, CELL_HEIGHT, cell.x, cell.y);
  311.         XCopyArea(display.display, sptr->image, display.back, GCN(GC_OR),
  312.         0, 0, CELL_WIDTH, CELL_HEIGHT, cell.x, cell.y);
  313.       }
  314.   }
  315.   /*}}}*/
  316.   /*{{{  initialize stuff*/
  317.   {
  318.     global.cherries = 5 * 8;
  319.     global.difficulty = player.screen + DIFFICULTY_PEDESTAL;
  320.     monster.normals = player.screen >= 3 ? 8 : 6;
  321.     update.back.backs = 0;
  322.     update.score.scores = 0;
  323.   }
  324.   /*}}}*/
  325.   XCopyArea(display.display, display.back, display.copy, GCN(GC_COPY),
  326.       0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, 0, 0);
  327.   return;
  328. }
  329. /*}}}*/
  330. /*{{{  void refresh_window()*/
  331. extern void refresh_window FUNCARGVOID
  332. /*
  333.  * refreshes the display window
  334.  */
  335. {
  336.   XCopyArea(display.display, display.copy, display.window, GCN(GC_COPY), 
  337.       0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, 0, 0);
  338.   xor_ball();
  339.   XDrawLine(display.display, display.window, GCN(GC_BALL),
  340.       WINDOW_WIDTH - global.missed, WINDOW_HEIGHT - 1,
  341.       WINDOW_WIDTH, WINDOW_HEIGHT - 1);
  342.   return;
  343. }
  344. /*}}}*/
  345. /*{{{  void show_updates()*/
  346. extern void show_updates FUNCARGVOID
  347. /*
  348.  * shows all the updates on the update list
  349.  */
  350. {
  351.   xor_ball();
  352.   /*{{{  backgrounds to copy*/
  353.   {
  354.     unsigned  i;
  355.     BACKGROUND *bptr;
  356.     
  357.     for(bptr = update.back.list, i = update.back.backs; i--; bptr++)
  358.       XCopyArea(display.display, display.back, display.copy, GCN(GC_COPY),
  359.       bptr->place.x, bptr->place.y, bptr->size.x, bptr->size.y,
  360.       bptr->place.x, bptr->place.y);
  361.   }
  362.   /*}}}*/
  363.   /*{{{  do the monster backgrounds*/
  364.   {
  365.     int       i;
  366.     MONSTER   *mptr;
  367.       
  368.     for(mptr = monster.list, i = monster.monsters; i--; mptr++)
  369.       {
  370.     int   new;
  371.       
  372.     update.set = 0;
  373.     if(mptr->type == 5)
  374.       new = 0;
  375.     else if(mptr->type > 5)
  376.       new = mptr->type;
  377.     else if(mptr->chew)
  378.       new = SPRITE_CHOMP + mptr->image;
  379.     else if(mptr->face >= 8)
  380.       new = SPRITE_SQUISHED - 8 + mptr->type * 2 + mptr->face;
  381.     else
  382.       new = SPRITE_MONSTERS + mptr->type * (6 * MONSTER_IMAGES) +
  383.           mptr->face * MONSTER_IMAGES + mptr->image;
  384.     if(mptr->old_sprite && (new != mptr->old_sprite ||
  385.         mptr->pixel.x != mptr->old_pixel.x ||
  386.         mptr->pixel.y != mptr->old_pixel.y ||
  387.         (mptr == &monster.list[0] &&
  388.           !player.old_ball.state && player.ball.state)))
  389.       {
  390.         XCopyArea(display.display, display.back, display.copy, GCN(GC_COPY),
  391.         mptr->old_pixel.x, mptr->old_pixel.y, CELL_WIDTH, CELL_HEIGHT,
  392.         mptr->old_pixel.x, mptr->old_pixel.y);
  393.         if(mptr->pixel.x != mptr->old_pixel.x ||
  394.         mptr->pixel.y != mptr->old_pixel.y || !new)
  395.           bounding_box(mptr->old_pixel.x, mptr->old_pixel.y,
  396.           CELL_WIDTH, CELL_HEIGHT);
  397.       }
  398.     if(new)
  399.       {
  400.         mptr->old_pixel.x = mptr->pixel.x;
  401.         mptr->old_pixel.y = mptr->pixel.y;
  402.         mptr->old_sprite = new;
  403.         bounding_box(mptr->old_pixel.x, mptr->old_pixel.y,
  404.         CELL_WIDTH, CELL_HEIGHT);
  405.       }
  406.     else
  407.       {
  408.         memmove(mptr, mptr + 1, i * sizeof(MONSTER));
  409.         mptr--;
  410.         monster.monsters--;
  411.       }
  412.     if(update.set)
  413.       add_background(update.tl.x, update.tl.y,
  414.           update.br.x - update.tl.x, update.br.y - update.tl.y);
  415.       }
  416.   }
  417.   /*}}}*/
  418.   /*{{{  do the apple backgrounds*/
  419.   {
  420.     int       i;
  421.     APPLE     *aptr;
  422.       
  423.     for(aptr = apple.list, i = apple.apples; i--; aptr++)
  424.       {
  425.     int   new;
  426.       
  427.     update.set = 0;
  428.     new = aptr->state;
  429.     if(new != aptr->old_state || aptr->pixel.x != aptr->old_pixel.x ||
  430.         aptr->pixel.y != aptr->old_pixel.y)
  431.       {
  432.         APPLE_SIZE const *asp;
  433.         int       x, y;
  434.         int       width, height;
  435.       
  436.         asp = &apple_sizes[aptr->old_state];
  437.         x = aptr->old_pixel.x + asp->offset.x;
  438.         y = aptr->old_pixel.y + asp->offset.y;
  439.         width = asp->size.x;
  440.         height = asp->size.y;
  441.         XCopyArea(display.display, display.back, display.copy, GCN(GC_COPY),
  442.         x, y, width, height, x, y);
  443.         bounding_box(x, y, width, height);
  444.       }
  445.     if(new != 6)
  446.       {
  447.         APPLE_SIZE const *asp;
  448.           
  449.         aptr->old_pixel.x = aptr->pixel.x;
  450.         aptr->old_pixel.y = aptr->pixel.y;
  451.         aptr->old_state = new;
  452.         asp = &apple_sizes[new];
  453.         bounding_box(aptr->old_pixel.x + asp->offset.x,
  454.         aptr->old_pixel.y + asp->offset.y, asp->size.x, asp->size.y);
  455.       }
  456.     else
  457.       {
  458.         unsigned  j;
  459.         MONSTER   *mptr;
  460.       
  461.         for(mptr = monster.list, j =  monster.monsters; j--; mptr++)
  462.           if(!mptr->apple)
  463.         /*EMPTY*/;
  464.           else if(mptr->apple == aptr)
  465.         mptr->apple = NULL;
  466.           else if(mptr->apple > aptr)
  467.         mptr->apple--;
  468.         memmove(aptr, aptr + 1, i * sizeof(APPLE));
  469.         aptr--;
  470.         apple.apples--;
  471.       }
  472.     if(update.set)
  473.       add_background(update.tl.x, update.tl.y,
  474.           update.br.x - update.tl.x, update.br.y - update.tl.y);
  475.       }
  476.   }
  477.   /*}}}*/
  478.   /*{{{  do the apple sprites*/
  479.   {
  480.     int       i;
  481.     APPLE     *aptr;
  482.       
  483.     for(aptr = apple.list, i = apple.apples; i--; aptr++)
  484.       {
  485.     SPRITE    *sptr;
  486.     APPLE_SIZE const *asp;
  487.     int       x, y;
  488.     int       width, height;
  489.       
  490.     asp = &apple_sizes[aptr->old_state];
  491.     sptr = &sprites[SPRITE_APPLE + aptr->old_state];
  492.     x = aptr->old_pixel.x + asp->offset.x;
  493.     y = aptr->old_pixel.y + asp->offset.y;
  494.     width = asp->size.x;
  495.     height = asp->size.y;
  496.     XCopyArea(display.display, sptr->mask, display.copy, GCN(GC_MASK),
  497.         0, 0, width, height, x, y);
  498.     XCopyArea(display.display, sptr->image, display.copy, GCN(GC_OR),
  499.         0, 0, width, height, x, y);
  500.       }
  501.   }
  502.   /*}}}*/
  503.   /*{{{  do the monster sprites*/
  504.   {
  505.     int       i;
  506.     MONSTER   *mptr;
  507.       
  508.     for(mptr = &monster.list[monster.monsters - 1], i = monster.monsters; i--; mptr--)
  509.       {
  510.     SPRITE    *sptr;
  511.       
  512.     sptr = &sprites[mptr->old_sprite];
  513.     XCopyArea(display.display, sptr->mask, display.copy, GCN(GC_MASK),
  514.         0, 0, CELL_WIDTH, CELL_HEIGHT,
  515.         mptr->old_pixel.x, mptr->old_pixel.y);
  516.     XCopyArea(display.display, sptr->image, display.copy, GCN(GC_OR),
  517.         0, 0, CELL_WIDTH, CELL_HEIGHT,
  518.         mptr->old_pixel.x, mptr->old_pixel.y);
  519.       }
  520.   }
  521.   /*}}}*/
  522.   /*{{{  holding the ball?*/
  523.   if(!player.ball.state && player.ball.count < 8)
  524.     {
  525.       COORD const *hold;
  526.       
  527.       hold = &ball_hold[player.ball.count * MONSTER_IMAGES + player.ball.image];
  528.       if(display.foreground == COLOUR_WEIRD)
  529.     XCopyArea(display.display, sprites[SPRITE_BALL].mask,
  530.         display.copy, GCN(GC_MASK), 0, 0, BALL_WIDTH, BALL_HEIGHT,
  531.         player.ball.pixel.x + hold->x, player.ball.pixel.y + hold->y);
  532.       XCopyArea(display.display, sprites[SPRITE_BALL].image,
  533.       display.copy, GCN(GC_OR), 0, 0, BALL_WIDTH, BALL_HEIGHT,
  534.       player.ball.pixel.x + hold->x, player.ball.pixel.y + hold->y);
  535.     }
  536.   /*}}}*/
  537.   /*{{{  scores to copy*/
  538.   {
  539.     unsigned  i;
  540.     SCORE     *sptr;
  541.       
  542.     for(sptr = update.score.list, i = update.score.scores; i--; sptr++)
  543.       {
  544.     XCopyArea(display.display, sptr->mask, display.copy, GCN(GC_MASK),
  545.         0, 0, DIGIT_WIDTH * 4, DIGIT_HEIGHT,
  546.         sptr->place.x, sptr->place.y);
  547.     XCopyArea(display.display, sptr->image, display.copy, GCN(GC_OR),
  548.         0, 0, DIGIT_WIDTH * 4, DIGIT_HEIGHT,
  549.         sptr->place.x, sptr->place.y);
  550.       }
  551.   }
  552.   /*}}}*/
  553.   /*{{{  areas to window*/
  554.   {
  555.     unsigned  i;
  556.     BACKGROUND *bptr;
  557.     
  558.     for(bptr = update.back.list, i = update.back.backs; i--; bptr++)
  559.       XCopyArea(display.display, display.copy, display.window, GCN(GC_COPY),
  560.       bptr->place.x, bptr->place.y, bptr->size.x, bptr->size.y,
  561.       bptr->place.x, bptr->place.y);
  562.   }
  563.   /*}}}*/
  564.   /*{{{  scores to window*/
  565.   {
  566.     unsigned  i;
  567.     SCORE     *sptr;
  568.       
  569.     for(sptr = update.score.list, i = update.score.scores; i--; sptr++)
  570.       XCopyArea(display.display, display.copy, display.window, GCN(GC_COPY),
  571.       sptr->place.x, sptr->place.y, DIGIT_WIDTH * 4, DIGIT_HEIGHT,
  572.       sptr->place.x, sptr->place.y);
  573.   }
  574.   /*}}}*/
  575.   update.back.backs = 0;
  576.   memcpy(&player.old_ball, &player.ball, sizeof(BALL));
  577.   xor_ball();
  578.   XSync(display.display, False);
  579.   return;
  580. }
  581. /*}}}*/
  582. /*{{{  void text_size(text, length, tptr)*/
  583. extern void text_size FUNCARGLIST((text, length, tptr))
  584. char const *text  FUNCARGSEP
  585. unsigned  length  FUNCARGSEP
  586. TEXT      *tptr   FUNCARGTERM
  587. /*
  588.  * wraps up the XQueryTextExtents for us
  589.  */
  590. {
  591.   int       direction;
  592.   XCharStruct chars;
  593.   
  594.   XQueryTextExtents(display.display, font.font, text, length,
  595.       &direction, &tptr->ascent, &tptr->descent, &chars);
  596.   tptr->width = chars.width;
  597.   return;
  598. }
  599. /*}}}*/
  600. /*{{{  void xor_ball()*/
  601. static void xor_ball FUNCARGVOID
  602. /*
  603.  * draws the old ball on the window directly
  604.  * using the ball's gc
  605.  * if the ball is being held, then we don't draw it,
  606.  * as that's done differently to stop it flickering
  607.  */
  608. {
  609.   switch(player.old_ball.state)
  610.   {
  611.     /*{{{  case 0:*/
  612.     case 0:
  613.       break;
  614.     /*}}}*/
  615.     /*{{{  case 1:*/
  616.     case 1:
  617.     {
  618.       XCopyArea(display.display, ball_xor, display.window, GCN(GC_BALL),
  619.       0, 0, BALL_WIDTH, BALL_HEIGHT,
  620.       player.old_ball.pixel.x - BALL_WIDTH / 2,
  621.       player.old_ball.pixel.y - BALL_HEIGHT / 2);
  622.       break;
  623.     }
  624.     /*}}}*/
  625.     /*{{{  case 2: case 4:*/
  626.     case 2: case 4:
  627.     {
  628.       COORD     offset;
  629.       COORD     pixel;
  630.       unsigned  bits;
  631.     
  632.       pixel.x = player.old_ball.pixel.x - BALL_WIDTH / 2;
  633.       pixel.y = player.old_ball.pixel.y - BALL_HEIGHT / 2;
  634.       if(player.old_ball.count)
  635.     {
  636.       offset.x = player.old_ball.count * BALL_EX;
  637.       offset.y = player.old_ball.count * BALL_EY;
  638.       bits = 0xFF;
  639.       /*{{{  set clips*/
  640.       {
  641.         if(pixel.x < offset.x)
  642.           bits &= 0xF8;
  643.         if(pixel.y < offset.y)
  644.           bits &= 0x3E;
  645.         if(pixel.x + offset.x > BOARD_WIDTH)
  646.           bits &= 0x8F;
  647.         if(pixel.y + offset.y > BOARD_HEIGHT)
  648.           bits &= 0xE3;
  649.       }
  650.       /*}}}*/
  651.       /*{{{  do inner bits*/
  652.       {
  653.         if(bits & 0x01)
  654.           XCopyArea(display.display, ball_xor, display.window, GCN(GC_BALL),
  655.           0, 0, BALL_WIDTH, BALL_HEIGHT,
  656.           pixel.x - offset.x, pixel.y - offset.y);
  657.         if(bits & 0x02)
  658.           XCopyArea(display.display, ball_xor, display.window, GCN(GC_BALL),
  659.           0, 0, BALL_WIDTH, BALL_HEIGHT,
  660.           pixel.x - offset.x, pixel.y);
  661.         if(bits & 0x04)
  662.           XCopyArea(display.display, ball_xor, display.window, GCN(GC_BALL),
  663.           0, 0, BALL_WIDTH, BALL_HEIGHT,
  664.           pixel.x - offset.x, pixel.y + offset.y);
  665.         if(bits & 0x08)
  666.           XCopyArea(display.display, ball_xor, display.window, GCN(GC_BALL),
  667.           0, 0, BALL_WIDTH, BALL_HEIGHT,
  668.           pixel.x, pixel.y + offset.y);
  669.         if(bits & 0x10)
  670.           XCopyArea(display.display, ball_xor, display.window, GCN(GC_BALL),
  671.           0, 0, BALL_WIDTH, BALL_HEIGHT,
  672.           pixel.x + offset.x, pixel.y + offset.y);
  673.         if(bits & 0x20)
  674.           XCopyArea(display.display, ball_xor, display.window, GCN(GC_BALL),
  675.           0, 0, BALL_WIDTH, BALL_HEIGHT,
  676.           pixel.x + offset.x, pixel.y);
  677.         if(bits & 0x40)
  678.           XCopyArea(display.display, ball_xor, display.window, GCN(GC_BALL),
  679.           0, 0, BALL_WIDTH, BALL_HEIGHT,
  680.           pixel.x + offset.x, pixel.y - offset.y);
  681.         if(bits & 0x80)
  682.           XCopyArea(display.display, ball_xor, display.window, GCN(GC_BALL),
  683.           0, 0, BALL_WIDTH, BALL_HEIGHT,
  684.           pixel.x, pixel.y - offset.y);
  685.       }
  686.       /*}}}*/
  687.       offset.x *= 2;
  688.       offset.y *= 2;
  689.       /*{{{  set clips*/
  690.       {
  691.         if(pixel.x < offset.x)
  692.           bits &= 0xF8;
  693.         if(pixel.y < offset.y)
  694.           bits &= 0x3E;
  695.         if(pixel.x + offset.x > BOARD_WIDTH)
  696.           bits &= 0x8F;
  697.         if(pixel.y + offset.y > BOARD_HEIGHT)
  698.           bits &= 0xE3;
  699.       }
  700.       /*}}}*/
  701.       /*{{{  do outer bits*/
  702.       {
  703.         if(bits & 0x01)
  704.           XCopyArea(display.display, ball_xor, display.window, GCN(GC_BALL),
  705.           0, 0, BALL_WIDTH, BALL_HEIGHT,
  706.           pixel.x - offset.x, pixel.y - offset.y);
  707.         if(bits & 0x02)
  708.           XCopyArea(display.display, ball_xor, display.window, GCN(GC_BALL),
  709.           0, 0, BALL_WIDTH, BALL_HEIGHT,
  710.           pixel.x - offset.x, pixel.y);
  711.         if(bits & 0x04)
  712.           XCopyArea(display.display, ball_xor, display.window, GCN(GC_BALL),
  713.           0, 0, BALL_WIDTH, BALL_HEIGHT,
  714.           pixel.x - offset.x, pixel.y + offset.y);
  715.         if(bits & 0x08)
  716.           XCopyArea(display.display, ball_xor, display.window, GCN(GC_BALL),
  717.           0, 0, BALL_WIDTH, BALL_HEIGHT,
  718.           pixel.x, pixel.y + offset.y);
  719.         if(bits & 0x10)
  720.           XCopyArea(display.display, ball_xor, display.window, GCN(GC_BALL),
  721.           0, 0, BALL_WIDTH, BALL_HEIGHT,
  722.           pixel.x + offset.x, pixel.y + offset.y);
  723.         if(bits & 0x20)
  724.           XCopyArea(display.display, ball_xor, display.window, GCN(GC_BALL),
  725.           0, 0, BALL_WIDTH, BALL_HEIGHT,
  726.           pixel.x + offset.x, pixel.y);
  727.         if(bits & 0x40)
  728.           XCopyArea(display.display, ball_xor, display.window, GCN(GC_BALL),
  729.           0, 0, BALL_WIDTH, BALL_HEIGHT,
  730.           pixel.x + offset.x, pixel.y - offset.y);
  731.         if(bits & 0x80)
  732.           XCopyArea(display.display, ball_xor, display.window, GCN(GC_BALL),
  733.           0, 0, BALL_WIDTH, BALL_HEIGHT,
  734.           pixel.x, pixel.y - offset.y);
  735.       }
  736.       /*}}}*/
  737.     }
  738.       else
  739.     XCopyArea(display.display, ball_xor, display.window, GCN(GC_BALL),
  740.         0, 0, BALL_WIDTH, BALL_HEIGHT, pixel.x, pixel.y);
  741.       break;
  742.     }
  743.     /*}}}*/
  744.     /*{{{  case 3:*/
  745.     case 3:
  746.       break;
  747.     /*}}}*/
  748.   }
  749.   return;
  750. }
  751. /*}}}*/
  752. /*{{{  void zoom_board()*/
  753. extern void zoom_board FUNCARGVOID
  754. /* zooms out on the initial board */
  755. {
  756.   unsigned  count;
  757.     
  758.   XFillRectangle(display.display, display.copy, GCN(GC_CLEAR),
  759.       BORDER_LEFT + 1, BORDER_TOP + 1, BOARD_WIDTH - 2, BOARD_HEIGHT - 2);
  760.   XCopyArea(display.display, display.copy, display.window, GCN(GC_COPY),
  761.       0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, 0, 0);
  762.   XCopyArea(display.display, display.back, display.copy, GCN(GC_COPY),
  763.       BORDER_LEFT + 1, BORDER_TOP + 1, BOARD_WIDTH - 2, BOARD_HEIGHT - 2,
  764.       BORDER_LEFT + 1, BORDER_TOP + 1);
  765.   /*{{{  do the apple sprites*/
  766.   {
  767.     int       i;
  768.     APPLE     *aptr;
  769.       
  770.     for(aptr = apple.list, i = apple.apples; i--; aptr++)
  771.       {
  772.     SPRITE    *sptr;
  773.       
  774.     sptr = &sprites[SPRITE_APPLE];
  775.     XCopyArea(display.display, sptr->mask, display.copy, GCN(GC_MASK),
  776.         0, 0, CELL_WIDTH, CELL_HEIGHT, aptr->pixel.x, aptr->pixel.y);
  777.     XCopyArea(display.display, sptr->image, display.copy, GCN(GC_OR),
  778.         0, 0, CELL_WIDTH, CELL_HEIGHT, aptr->pixel.x, aptr->pixel.y);
  779.       }
  780.   }
  781.   /*}}}*/
  782.   timer_start(ZOOM_RATE);
  783.   for(count = 0; count < BOARD_HEIGHT / (2 * ZOOM_Y); count += 1)
  784.     {
  785.       XCopyArea(display.display, display.copy, display.window, GCN(GC_COPY),
  786.       BORDER_LEFT + BOARD_WIDTH / 2 - ZOOM_X - count * ZOOM_X,
  787.       BORDER_TOP + BOARD_HEIGHT / 2 - ZOOM_Y- count * ZOOM_Y,
  788.       ZOOM_X, count * 2 * ZOOM_Y + 2 * ZOOM_Y,
  789.       BORDER_LEFT + BOARD_WIDTH / 2 - ZOOM_X - count * ZOOM_X,
  790.       BORDER_TOP + BOARD_HEIGHT / 2 - ZOOM_Y - count * ZOOM_Y);
  791.       XCopyArea(display.display, display.copy, display.window, GCN(GC_COPY),
  792.       BORDER_LEFT + BOARD_WIDTH / 2 + count * ZOOM_X,
  793.       BORDER_TOP + BOARD_HEIGHT / 2 - ZOOM_Y - count * ZOOM_Y,
  794.       ZOOM_X, count * 2 * ZOOM_Y + 2 * ZOOM_Y,
  795.       BORDER_LEFT + BOARD_WIDTH / 2 + count * ZOOM_X,
  796.       BORDER_TOP + BOARD_HEIGHT / 2 - ZOOM_Y - count * ZOOM_Y);
  797.       XCopyArea(display.display, display.copy, display.window, GCN(GC_COPY),
  798.       BORDER_LEFT + BOARD_WIDTH / 2 - count * ZOOM_X,
  799.       BORDER_TOP + BOARD_HEIGHT / 2 - ZOOM_Y - count * ZOOM_Y,
  800.       count * 2 * ZOOM_X, ZOOM_Y,
  801.       BORDER_LEFT + BOARD_WIDTH / 2 - count * ZOOM_X,
  802.       BORDER_TOP + BOARD_HEIGHT / 2 - ZOOM_Y - count * ZOOM_Y);
  803.       XCopyArea(display.display, display.copy, display.window, GCN(GC_COPY),
  804.       BORDER_LEFT + BOARD_WIDTH / 2 - count * ZOOM_X,
  805.       BORDER_TOP + BOARD_HEIGHT / 2 + count * ZOOM_Y,
  806.       count * 2 * ZOOM_X, ZOOM_Y,
  807.       BORDER_LEFT + BOARD_WIDTH / 2 - count * ZOOM_X,
  808.       BORDER_TOP + BOARD_HEIGHT / 2 + count * ZOOM_Y);
  809.       XSync(display.display, False);
  810.       timer_wait();
  811.     }
  812.   timer_stop();
  813.   return;
  814. }
  815. /*}}}*/
  816.